import os
import io
from pathlib import Path
from PIL import Image
import logging

logger = logging.getLogger('api')

class ImageProcessor:
    """
    图像处理工具类，用于压缩和转换图像格式
    """
    
    @staticmethod
    def compress_image(input_image, output_format='WEBP', quality=85, max_size=(800, 800), target_size_kb=50):
        """
        压缩图像并转换为指定格式
        
        参数:
            input_image: 输入图像（文件路径或Image对象）
            output_format: 输出格式，默认为WEBP
            quality: 输出质量，1-100，默认85
            max_size: 最大尺寸，默认(800, 800)
            target_size_kb: 目标文件大小（KB），默认50KB
        
        返回:
            BytesIO对象
        """
        if isinstance(input_image, str):
            # 如果输入是文件路径
            img = Image.open(input_image)
            logger.info(f"从路径加载图像: {input_image}")
        elif isinstance(input_image, Image.Image):
            # 如果输入是Image对象
            img = input_image
            logger.info("处理已加载的Image对象")
        else:
            # 尝试作为文件对象处理
            img = Image.open(input_image)
            logger.info("从文件对象加载图像")
        
        # 记录原始尺寸
        original_size = img.size
        logger.info(f"原始尺寸: {original_size[0]}x{original_size[1]}像素, 模式: {img.mode}")
        
        # 转换为RGB模式（处理RGBA或其他模式）
        if img.mode != 'RGB':
            img = img.convert('RGB')
            logger.info(f"将图像模式从 {img.mode} 转换为 RGB")
        
        # 调整图像大小
        if original_size[0] > max_size[0] or original_size[1] > max_size[1]:
            img.thumbnail(max_size, Image.Resampling.LANCZOS)
            logger.info(f"调整图像尺寸为: {img.size[0]}x{img.size[1]}像素")
        else:
            logger.info(f"图像尺寸已在限制范围内，无需调整")
        
        # 初始质量设置
        current_quality = quality
        output_buffer = io.BytesIO()
        
        # 迭代尝试不同的质量值，直到达到目标大小
        attempts = 0
        while current_quality > 10:  # 最低质量设为10
            attempts += 1
            output_buffer = io.BytesIO()
            img.save(output_buffer, format=output_format, quality=current_quality, optimize=True)
            
            # 检查当前大小
            file_size_kb = len(output_buffer.getvalue()) / 1024
            
            if file_size_kb <= target_size_kb * 1.1:  # 允许比目标大小大10%
                logger.info(f"图像压缩成功: {file_size_kb:.2f}KB，质量为{current_quality}，尝试次数: {attempts}")
                break
            
            # 降低质量再试
            previous_quality = current_quality
            current_quality -= 5
            logger.debug(f"压缩尝试 #{attempts}: 当前大小 {file_size_kb:.2f}KB > 目标 {target_size_kb}KB，质量从 {previous_quality} 降低到 {current_quality}")
        
        if current_quality <= 10:
            logger.warning(f"无法将图像压缩到目标大小 {target_size_kb}KB，最终大小: {file_size_kb:.2f}KB，质量已降至最低值 {current_quality}")
        
        # 返回到开始位置
        output_buffer.seek(0)
        return output_buffer

    @staticmethod
    def process_uploaded_file(uploaded_file, target_format='WEBP', target_size_kb=50, max_size=(800, 800), quality=85):
        """
        处理上传的文件，压缩并转换格式
        
        参数:
            uploaded_file: Django UploadedFile对象
            target_format: 目标格式，默认为WEBP
            target_size_kb: 目标文件大小（KB），默认50KB
            max_size: 最大尺寸，默认(800, 800)
            quality: 初始质量，1-100，默认85
            
        返回:
            BytesIO对象
        """
        try:
            # 记录原始文件信息
            original_size = uploaded_file.size / 1024  # KB
            logger.info(f"处理上传文件: {uploaded_file.name}, 原始大小: {original_size:.2f}KB")
            
            # 打开图像
            img = Image.open(uploaded_file)
            original_dimensions = img.size
            logger.info(f"原始图像尺寸: {original_dimensions[0]}x{original_dimensions[1]}像素")
            
            # 压缩图像
            compressed_image = ImageProcessor.compress_image(
                img, 
                output_format=target_format, 
                target_size_kb=target_size_kb,
                max_size=max_size,
                quality=quality
            )
            
            # 记录压缩后的信息
            compressed_size = len(compressed_image.getvalue()) / 1024
            logger.info(f"压缩后大小: {compressed_size:.2f}KB, 压缩率: {(compressed_size/original_size*100):.2f}%")
            
            return compressed_image
        except Exception as e:
            logger.error(f"处理上传图像时出错: {str(e)}")
            raise
    
    @staticmethod
    def batch_convert_directory(directory_path, target_format='WEBP', target_size_kb=50):
        """
        批量转换目录中的所有图像
        
        参数:
            directory_path: 目录路径
            target_format: 目标格式，默认为WEBP
            target_size_kb: 目标文件大小（KB），默认50KB
        """
        directory = Path(directory_path)
        if not directory.exists() or not directory.is_dir():
            logger.error(f"目录不存在: {directory_path}")
            return
        
        # 图像文件扩展名
        image_extensions = {'.jpg', '.jpeg', '.png', '.gif', '.bmp'}
        
        # 遍历目录中的所有文件
        for file_path in directory.glob('**/*'):
            if file_path.is_file() and file_path.suffix.lower() in image_extensions:
                try:
                    # 构建新文件名
                    new_path = file_path.with_suffix(f'.webp')
                    
                    # 如果目标文件已存在，则跳过
                    if new_path.exists():
                        logger.info(f"跳过已存在的文件: {new_path}")
                        continue
                    
                    # 压缩并转换图像
                    logger.info(f"处理文件: {file_path}")
                    compressed_image = ImageProcessor.compress_image(
                        str(file_path),
                        output_format=target_format,
                        target_size_kb=target_size_kb
                    )
                    
                    # 保存新文件
                    with open(new_path, 'wb') as f:
                        f.write(compressed_image.getvalue())
                    
                    logger.info(f"成功转换: {file_path} -> {new_path}")
                    
                    # 移除原文件（可选）
                    # file_path.unlink()
                    
                except Exception as e:
                    logger.error(f"处理文件 {file_path} 时出错: {str(e)}") 